﻿using System.IO;
using System.Threading;
using PerfAnalyzerLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace UnitTests
{
    /// <summary>
    ///This is a test class for PerfLogManagerTest and is intended
    ///to contain all PerfLogManagerTest Unit Tests
    ///</summary>
	[TestClass()]
	public class PerfLogManagerTest
	{
		// Used for unit testing event handlers
		ManualResetEvent _parseTest = new ManualResetEvent(false);

		private TestContext testContextInstance;

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		#region Additional test attributes
		// 
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		//[ClassInitialize()]
		//public static void MyClassInitialize(TestContext testContext)
		//{
		//}
		//
		//Use ClassCleanup to run code after all tests in a class have run
		//[ClassCleanup()]
		//public static void MyClassCleanup()
		//{
		//}
		//
		//Use TestInitialize to run code before running each test
		//[TestInitialize()]
		//public void MyTestInitialize()
		//{
		//}
		//
		//Use TestCleanup to run code after each test has run
		//[TestCleanup()]
		//public void MyTestCleanup()
		//{
		//}
		//
		#endregion

		/// <summary>
		///A test for AddCounter
		///</summary>
		[TestMethod]
		public void PerfLogManager_AddCounter()
		{
			PerfLogManager.ClearPerflogList();


			string filename1 = CreatePerflog();
			string filename2 = CreatePerflog();

			Assert.AreEqual(0, PerfLogManager.PerfLogs.Count);
			
			PerfLogManager.AddPerfLog(filename1);
			Assert.AreEqual(1, PerfLogManager.PerfLogs.Count);

			PerfLogManager.AddPerfLog(filename2);
			Assert.AreEqual(2, PerfLogManager.PerfLogs.Count);

			File.Delete(filename1);
			File.Delete(filename2);
		}

		/// <summary>
		/// Adding the same perflog twice.
		///</summary>
		[TestMethod]
		public void PerfLogManager_AddCounter_AddSameFile()
		{
			PerfLogManager.ClearPerflogList();

			string filename = CreatePerflog();

			PerfLogManager.AddPerfLog(filename);
			PerfLogManager.AddPerfLog(filename);

			Assert.AreEqual(1, PerfLogManager.PerfLogs.Count);

			File.Delete(filename);
		}

		/// <summary>
		/// Exception test, adding filename as null.
		///</summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentException))]
		public void PerfLogManager_AddCounter_ExceptionAddingNull()
		{
			PerfLogManager.ClearPerflogList();
			PerfLogManager.AddPerfLog(null);
		}

		/// <summary>
		/// Exception test, adding a file that does not exists.
		///</summary>
		[TestMethod]
		[ExpectedException(typeof(FileNotFoundException))]
		public void PerfLogManager_AddCounter_ExceptionFileNotFound()
		{
			PerfLogManager.ClearPerflogList();
			PerfLogManager.AddPerfLog("c:\nonExistanceFile.csv");
		}

		/// <summary>
		/// Clearing the perflog list.
		///</summary>
		[TestMethod]
		public void PerfLogManager_ClearPerflogList()
		{
			PerfLogManager.ClearPerflogList();

			string filename = CreatePerflog();

			Assert.AreEqual(0, PerfLogManager.PerfLogs.Count);

			PerfLogManager.AddPerfLog(filename);
			Assert.AreEqual(1, PerfLogManager.PerfLogs.Count);

			PerfLogManager.ClearPerflogList();
			Assert.AreEqual(0, PerfLogManager.PerfLogs.Count);

			File.Delete(filename);
		}

		/// <summary>
		/// Parsing a file.
		///</summary>
		[TestMethod]
		public void PerfLogManager_Parse()
		{
			PerfLogManager.ClearPerflogList();

			string filename = CreatePerflog();

			PerfLogManager.AddPerfLog(filename);

			Assert.AreEqual(0, PerfLogManager.PerfLogs[0].Counters.Count);

			ParseWait();
			
			Assert.AreNotEqual(0, PerfLogManager.PerfLogs[0].Counters.Count);

			File.Delete(filename);
		}

		/// <summary>
		/// A test for Export.
		/// </summary>
		[TestMethod]
		public void PerfLogManager_Export()
		{
			PerfLogManager.ClearPerflogList();

			string filename1 = CreatePerflog();
			string filename2 = CreatePerflog();
			string filename3 = CreatePerflog();

			PerfLogManager.AddPerfLog(filename1);
			PerfLogManager.AddPerfLog(filename2);
			PerfLogManager.AddPerfLog(filename3);
			ParseWait();

			// This file should be deleted during the export process.
			string output = GeneratorCsvFile.GenerateEmptyFile();

			PerfLogManager.Export(output);

			var fi = new FileInfo(output);

			Assert.AreNotEqual(0, fi.Length);

			// Read file and counts the number of columns.
			using (var sr = new StreamReader(output))
			{
				string line = sr.ReadLine();
				int columnsCount = line.Split(',').Length;

				while ((line = sr.ReadLine()) != null)
				{
					Assert.AreEqual(columnsCount, line.Split(',').Length);
				}
			}

			File.Delete(output);
			File.Delete(filename1);
			File.Delete(filename2);
			File.Delete(filename3);
			PerfLogManager.ClearPerflogList();
		}

		/// <summary>
		/// A test for IsFileInList
		///</summary>
		[TestMethod]
		public void PerfLogManager_IsFileInListTest()
		{
			PerfLogManager.ClearPerflogList();

			string filename = CreatePerflog();

			Assert.AreEqual(false, PerfLogManager.IsFileInList(filename));

			PerfLogManager.AddPerfLog(filename);
			Assert.AreEqual(true, PerfLogManager.IsFileInList(filename));

			PerfLogManager.ClearPerflogList();
			Assert.AreEqual(false, PerfLogManager.IsFileInList(filename));

			File.Delete(filename);
		}

		/// <summary>
		/// Call Parse on the PerfLogManager and wait for completion.
		/// </summary>
		private void ParseWait()
		{
			PerfLogManager.ParsingCompleted += ParsingCompleted;
			PerfLogManager.Parse();
			_parseTest.WaitOne();
		}

		/// <summary>
		/// Used for event handler unit testing.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ParsingCompleted(object sender, EventArgs e)
		{
			_parseTest.Set();
		}

		/// <summary>
		/// Create a small perflog and return its filename.
		/// </summary>
		/// <returns>Filename of the new perflog.</returns>
		private static string CreatePerflog()
		{
			var counters = new List<Counter>();
			counters.Add(GeneratorCounter.GenerateIncrementalCounter(GeneratorCounterInfo.GenerateCounterInfo(1, 1, 1, 1), -10, 20));
			counters.Add(GeneratorCounter.GenerateIncrementalCounter(GeneratorCounterInfo.GenerateCounterInfo(1, 1, 1, 2), 0, 20));
			counters.Add(GeneratorCounter.GenerateIncrementalCounter(GeneratorCounterInfo.GenerateCounterInfo(1, 1, 1, 3), 10, 20));
			return GeneratorCsvFile.GenerateCsvFile(counters, true);
		}
	}
}
